﻿#include "domainobject.h"
#include "memcached.h"
#include "config.h"
#include "gyscada.h"
#include"qdebug.h"
#include<qtextcodec.h>
/*
#include <QtDebug>
#include <QMessageBox>
*/

// DomainObject
DomainObject::DomainObject(DomainObject* parent)
{
    this->parent = parent;

    QTextCodec* code=QTextCodec::codecForName("utf-8");

    QTextCodec::setCodecForLocale(code);
}

// Control Interface

void DomainObject::setControlInfos(const QMap<int, ControlInfo> &controls)
{
    this->controls = controls;
}

const QMap<int, ControlInfo>& DomainObject::getControlInfos()
{
    return controls;
}

// DomainObjectCollection
DomainObjectCollection::DomainObjectCollection(DomainObject* parent)
    : DomainObject(parent)
{
}


void DomainObjectCollection::addChild(DomainObject *domainObject)
{
    if (domainObject != NULL) {
        children.append(domainObject);
    }
}

int DomainObjectCollection::getNumberOfDescendant()
{
    int count = 0;

    for (QList<DomainObject*>::iterator it = children.begin(); it != children.end(); ++it) {
        count += (*it)->getNumberOfDescendant();
    }

    return count;
}

QList<DomainObject*> DomainObjectCollection::getDescendant()
{
    QList<DomainObject*> domainObjects;

    for (QList<DomainObject*>::iterator it = children.begin(); it != children.end(); ++it) {
        domainObjects.append((*it)->getDescendant());
    }

    return domainObjects;
}

QList<QString> DomainObjectCollection::getDescription()
{
    QList<QString> descriptions;

    for (QList<DomainObject*>::iterator it = children.begin(); it != children.end(); ++it) {
        descriptions.append((*it)->getDescription());
    }

    return descriptions;
}

QList<QString> DomainObjectCollection::getCheckedDescription()
{
    QList<QString> descriptions;

    for (QList<DomainObject*>::iterator it = children.begin(); it != children.end(); ++it) {
        descriptions.append((*it)->getCheckedDescription());
    }

    return descriptions;
}

void DomainObjectCollection::setChecked()
{
    for (QList<DomainObject*>::iterator it = children.begin(); it != children.end(); ++it) {
        (*it)->setChecked();
    }
}

/*void DomainObjectCollection::setUNChecked()
{

}*/

void DomainObjectCollection::cleanChecked()
{
    for (QList<DomainObject*>::iterator it = children.begin(); it != children.end(); ++it) {
        (*it)->cleanChecked();
    }
}

void DomainObjectCollection::invertChecked()
{
    for (QList<DomainObject*>::iterator it = children.begin(); it != children.end(); ++it) {
        (*it)->invertChecked();
    }
}

int DomainObjectCollection::countChecked()
{
    int count = 0;
    for (QList<DomainObject*>::iterator it = children.begin(); it != children.end(); ++it) {
        count += (*it)->countChecked();
    }

    return count;
}

void DomainObjectCollection::setName(const QString& name)
{
    this->name = name;
}

const QString& DomainObjectCollection::getName()
{
    return this->name;
}

DomainObject* DomainObjectCollection::getParent()
{
    return this->parent;
}

QList<int> DomainObjectCollection::getControlValues(int id)
{
    QList<int> values;

    if (!this->controls.contains(id)) {
        return QList<int>();
    }

    if (this->controls[id].supported) {
        for (QList<DomainObject*>::iterator it = this->children.begin();
             it != this->children.end();
             ++it) {
            values << (*it)->getControlValues(id);
        }
    } else {
        values.append(this->controls[id].value);
    }

    return values;
}

QList<int> DomainObjectCollection::getControlAddrs(int id)
{
    QList<int> addrs;

    if (!this->controls.contains(id)) {
        return QList<int>();
    }

    if (this->controls[id].supported) {
        for (QList<DomainObject*>::iterator it = this->children.begin();
             it != this->children.end();
             ++it) {
            addrs << (*it)->getControlAddrs(id);
        }
    } else {
        addrs.append(this->controls[id].addr);
    }

    return addrs;
}

bool DomainObjectCollection::doControl(int id)
{
    bool ret = true;

    if (!this->controls.contains(id)) {
        return false;
    }

    if (this->controls[id].supported) {
        QList<int> addrList = getControlAddrs(id);
        QList<int> valueList = getControlValues(id);

        libgyscada_control_type_t   types[1024];
        uint32_t                    addrs[1024];
        uint32_t                    values[1024];
        void*                       valuePoints[1024];
        libgyscada_control_error_t  errors[1024];
        int i = 0;
        
        for (i = 0; i < addrList.length(); ++i) {
            types[i] = CONTROL_TYPE_YK;
            addrs[i] = addrList.at(i);
            values[i] = valueList.at(i);
            valuePoints[i] = &values[i];
            errors[i] = CONTROL_SUCCESS;
        }

        return GYSCADA::getInstance()->control(
            types, addrs, valuePoints, errors, addrList.length());
    } else {
        libgyscada_control_error_t error;
        return GYSCADA::getInstance()->control(
                CONTROL_TYPE_YK, this->controls[id].addr, &this->controls[id].value, &error);
    }

    return true;
}

bool DomainObjectCollection::doControl(int id, double value)
{
    bool ret = true;

    if (!this->controls.contains(id)) {
        return false;
    }

    if (this->controls[id].supported) {
        QList<int> addrList = getControlAddrs(id);

        libgyscada_control_type_t   types[1024];
        uint32_t                    addrs[1024];
        float                       values[1024];
        void*                       valuePoints[1024];
        libgyscada_control_error_t  errors[1024];
        int i = 0;
        
        for (i = 0; i < addrList.length(); ++i) {
            types[i] = CONTROL_TYPE_YT;
            addrs[i] = addrList.at(i);
            values[i] = (float)value;
            valuePoints[i] = &values[i];
            errors[i] = CONTROL_SUCCESS;
        }

        return GYSCADA::getInstance()->control(
            types, addrs, valuePoints, errors, addrList.length());
    } else {
        libgyscada_control_error_t error;
        float tmp = (float)value;
        return GYSCADA::getInstance()->control(
                CONTROL_TYPE_YT, this->controls[id].addr, &tmp, &error);
    }

    return true;
}

// DomainObjectStation
DomainObjectStation::DomainObjectStation(DomainObject* parent)
    : DomainObjectCollection(parent)
{
}

// DomainObjectLine
DomainObjectLine::DomainObjectLine(DomainObject* parent)
    : DomainObjectCollection(parent)
{
}

// DomainObjectTurbine
DomainObjectTurbine::DomainObjectTurbine(DomainObject* parent)
    : DomainObject(parent)
{
}

int DomainObjectTurbine::getNumberOfDescendant()
{
    return 1;
}

QList<DomainObject*> DomainObjectTurbine::getDescendant()
{
    QList<DomainObject*> domainObjects;
    domainObjects.append(this);

    return domainObjects;
}

QList<QString> DomainObjectTurbine::getDescription()
{
    QString         description;
    QList<QString>  descriptions;
    DomainObject*   obj = this;

    while (obj != NULL) {
        description = description.isEmpty() ? obj->getName() : obj->getName() + " " + description;
        obj = obj->getParent();
        descriptions.append(description);
    }

    return descriptions;
}

QList<QString> DomainObjectTurbine::getCheckedDescription()
{
    QString         description;
    QList<QString>  descriptions;
    DomainObject*   obj = this;

    if (this->checkState == Qt::Checked) {
        while (obj != NULL) {
            description = description.isEmpty() ? obj->getName() : obj->getName() + " " + description;
            obj = obj->getParent();
        }
        descriptions.append(description);
    }

    return descriptions;
}

// Point interface
void DomainObjectTurbine::setPointsAddr(const QMap<int, QString>& pointsAddr)
{
    points = pointsAddr;
   // qDebug()<<"points";
    for(int i=0;i<points.count();i++){

        //qDebug()<<points.value(i)<<"  ";
    }

   // qDebug()<<endl;
}

QVariant DomainObjectTurbine::getPointValue(int id)
{
    if (points.contains(id)) {
        bool ok = false;
        double value = MemCached::getInstance()->getValue(points[id], &ok);
        if (ok) {

          //   qDebug()<<"pointValue:"<<value<<endl;
            return value;

        } else {
            return QVariant();
        }
    } else {
        return QVariant();
    }
}

void DomainObjectTurbine::setName(const QString& name)
{
    this->name = name;
}

const QString& DomainObjectTurbine::getName()
{
    return this->name;
}

DomainObject* DomainObjectTurbine::getParent()
{
    return this->parent;
}

// Set/Get Transition
void DomainObjectTurbine::setStatePointId(int id)
{
    this->statePointId = id;
}

int DomainObjectTurbine::getStatePointId()
{
    return this->statePointId;
}

void DomainObjectTurbine::setTransition(const QMap<int, int>& transition)
{
    this->transition = transition;

  /*  qDebug()<<"transition";
    for(int i=0;i<transition.count();i++){
        qDebug()<<transition.value(i);
    }
    qDebug()<<endl;*/
}

void DomainObjectTurbine::setDefaultState(int defaultstate)
{
    this->defaultState = defaultstate;
}

QString DomainObjectTurbine::getState()
{
    QString& addrState = points[statePointId];

    bool ok = false;
    double value = MemCached::getInstance()->getValue(addrState, &ok);
    if (ok) {
        if (transition.contains((int)value)) {
            return GYSCADAConfig::getInstance()->getStateTitle(transition[(int)value]);
        } else {
            return GYSCADAConfig::getInstance()->getStateTitle(defaultState);
        }
    } else {
        return QString();
    }
}

QColor DomainObjectTurbine::getStateColor()
{
    QString& addrState = points[statePointId];

    bool ok = false;
    double value = MemCached::getInstance()->getValue(addrState, &ok);
    if (ok) {
        if (transition.contains((int)value)) {
            return GYSCADAConfig::getInstance()->getStateColor(transition[(int)value]);
        } else {
            return GYSCADAConfig::getInstance()->getStateColor(defaultState);
        }
    } else {
        return QColor();
    }
}

QIcon DomainObjectTurbine::getStateIcon()
{
    QString& addrState = points[statePointId];

    bool ok = false;
    double value = MemCached::getInstance()->getValue(addrState, &ok);
    if (ok && transition.contains((int)value)) {
        return GYSCADAConfig::getInstance()->getStateIcon(transition[(int)value]);
    } else {
        return GYSCADAConfig::getInstance()->getStateIcon(defaultState);
    }
}

void DomainObjectTurbine::setChecked()
{
    this->checkState = Qt::Checked;
}

void DomainObjectTurbine::cleanChecked()
{
    this->checkState = Qt::Unchecked;
   // qDebug()<<this->checkState;
}

void DomainObjectTurbine::invertChecked()
{
    if (this->checkState == Qt::Checked) {
        this->checkState = Qt::Unchecked;
    } else {
        this->checkState = Qt::Checked;
    }
   //  qDebug()<<this->checkState;
}

int DomainObjectTurbine::countChecked()
{
    return this->checkState == Qt::Checked ? 1 : 0;
    // qDebug()<<this->checkState;
}

Qt::CheckState DomainObjectTurbine::getCheckState()
{
    return this->checkState;
}

QList<int> DomainObjectTurbine::getControlValues(int id)
{
    if (this->checkState == Qt::Checked &&
        this->controls.contains(id)) {

        QList<int> values;
        values << this->controls[id].value;

        return values;
    }

    return QList<int>();
}

QList<int> DomainObjectTurbine::getControlAddrs(int id)
{
    if (this->checkState == Qt::Checked &&
        this->controls.contains(id)) {

        QList<int> addrs;
        addrs << this->controls[id].addr;

        return addrs;
    }

    return QList<int>();
}

bool DomainObjectTurbine::doControl(int id, double value)
{
    if (!this->controls.contains(id)) {
        return false;
    }

    if (this->checkState == Qt::Checked) {
        qDebug()<<"doControlID"<<id<<value;
        libgyscada_control_error_t error;
        float tmp = (float)value;
        return GYSCADA::getInstance()->control(
                CONTROL_TYPE_YT, this->controls[id].addr, &tmp, &error);
    }

    return true;
}

bool DomainObjectTurbine::doControl(int id)
{
    if (!this->controls.contains(id)) {
        return false;
    }

    if (this->checkState == Qt::Checked) {
        // Don't check control style
        qDebug()<<"doControlID"<<id;
        libgyscada_control_error_t error;
        return GYSCADA::getInstance()->control(
                CONTROL_TYPE_YK, this->controls[id].addr, &this->controls[id].value, &error);
    }

    return true;
}
